#ifndef INTERPOLATION_METHODS_H
#define INTERPOLATION_METHODS_H

#include <array>

#include "utils/TriangleUtils.h"

#ifdef ENOKI_AVAILABLE
#include "enoki/array.h"
#endif

namespace sdflib
{
struct NoneInterpolation
{
    static constexpr uint32_t VALUES_PER_VERTEX = 0;
    static constexpr uint32_t EXTRA_VALUES = 0;
    static constexpr uint32_t NUM_COEFFICIENTS = 0;

    inline static void calculateCoefficients(const std::array<std::array<float, VALUES_PER_VERTEX>, 8>& valuesPerVertex,
                                      float nodeSize,
                                      const std::vector<uint32_t>& triangles,
                                      const Mesh& mesh,
                                      const std::vector<TriangleUtils::TriangleData>& trianglesData,
                                      std::array<float, NUM_COEFFICIENTS>& outCoefficients) {}

    inline static void calculatePointValues(glm::vec3 point,
                                      uint32_t nearestTriangleIndex,
                                      const Mesh& mesh,
                                      const std::vector<TriangleUtils::TriangleData>& trianglesData, 
                                      std::array<float, VALUES_PER_VERTEX>& outValues)
    { }

    inline static float interpolateValue(const std::array<float, NUM_COEFFICIENTS>& coefficients, glm::vec3 fracPart) 
    {
        return 0.0f;
    }

    inline static glm::vec3 interpolateGradient(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        return glm::vec3(0.0f);
    }

    inline static void interpolateVertexValues(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart, float nodeSize, std::array<float, VALUES_PER_VERTEX>& outValues)
    {}
};

struct TriLinearInterpolation
{
    static constexpr uint32_t VALUES_PER_VERTEX = 1;
    static constexpr uint32_t EXTRA_VALUES = 0;
    static constexpr uint32_t NUM_COEFFICIENTS = 8;

    inline static void calculateCoefficients(const std::array<std::array<float, VALUES_PER_VERTEX>, 8>& valuesPerVertex,
                                             float nodeSize,
                                             const std::vector<uint32_t>& triangles,
                                             const Mesh& mesh,
                                             const std::vector<TriangleUtils::TriangleData>& trianglesData,
                                             std::array<float, NUM_COEFFICIENTS>& outCoefficients) 
    {
        outCoefficients = *reinterpret_cast<const std::array<float, NUM_COEFFICIENTS>*>(&valuesPerVertex);
    }

    inline static void calculatePointValues(glm::vec3 point,
                                      uint32_t nearestTriangleIndex,
                                      const Mesh& mesh,
                                      const std::vector<TriangleUtils::TriangleData>& trianglesData, 
                                      std::array<float, VALUES_PER_VERTEX>& outValues)
    { 
        outValues[0] = TriangleUtils::getSignedDistPointAndTriangle(point, trianglesData[nearestTriangleIndex]);
    }

    inline static float interpolateValue(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        float d00 = values[0] * (1.0f - fracPart.x) +
                values[1] * fracPart.x;
        float d01 = values[2] * (1.0f - fracPart.x) +
                    values[3] * fracPart.x;
        float d10 = values[4] * (1.0f - fracPart.x) +
                    values[5] * fracPart.x;
        float d11 = values[6] * (1.0f - fracPart.x) +
                    values[7] * fracPart.x;

        float d0 = d00 * (1.0f - fracPart.y) + d01 * fracPart.y;
        float d1 = d10 * (1.0f - fracPart.y) + d11 * fracPart.y;

        return d0 * (1.0f - fracPart.z) + d1 * fracPart.z;
    }

    inline static glm::vec3 interpolateGradient(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        float gx;
        {
            float d00 = values[0] * (1.0f - fracPart.y) +
                values[2] * fracPart.y;
            float d01 = values[1] * (1.0f - fracPart.y) +
                        values[3] * fracPart.y;
            float d10 = values[4] * (1.0f - fracPart.y) +
                        values[6] * fracPart.y;
            float d11 = values[5] * (1.0f - fracPart.y) +
                        values[7] * fracPart.y;

            float d0 = d00 * (1.0f - fracPart.z) + d10 * fracPart.z;
            float d1 = d01 * (1.0f - fracPart.z) + d11 * fracPart.z;

            gx = d1 - d0;
        }

        float gy;
        float gz;
        {
            float d00 = values[0] * (1.0f - fracPart.x) +
                values[1] * fracPart.x;
            float d01 = values[2] * (1.0f - fracPart.x) +
                        values[3] * fracPart.x;
            float d10 = values[4] * (1.0f - fracPart.x) +
                        values[5] * fracPart.x;
            float d11 = values[6] * (1.0f - fracPart.x) +
                        values[7] * fracPart.x;

            {
                float d0 = d00 * (1.0f - fracPart.z) + d10 * fracPart.z;
                float d1 = d01 * (1.0f - fracPart.z) + d11 * fracPart.z;

                gy = d1 - d0;
            }

            {
                float d0 = d00 * (1.0f - fracPart.y) + d01 * fracPart.y;
                float d1 = d10 * (1.0f - fracPart.y) + d11 * fracPart.y;

                gz = d1 - d0;
            }
        }

        return glm::vec3(gx, gy, gz);
    }

    inline static void interpolateVertexValues(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart, float nodeSize, std::array<float, VALUES_PER_VERTEX>& outValues)
    {
        outValues[0] = interpolateValue(values, fracPart);
    }
};

// struct TriCubicInterpolation
// {
//     static constexpr uint32_t VALUES_PER_VERTEX = 4;
//     static constexpr uint32_t EXTRA_VALUES = 0;
//     static constexpr uint32_t NUM_COEFFICIENTS = 64;

//     inline static void calculatePointValues(glm::vec3 point,
//                                       uint32_t nearestTriangleIndex,
//                                       const Mesh& mesh,
//                                       const std::vector<TriangleUtils::TriangleData>& trianglesData, 
//                                       std::array<float, VALUES_PER_VERTEX>& outValues)
//     {
//         const std::vector<uint32_t>& indices = mesh.getIndices();
//         const std::vector<glm::vec3>& vertices = mesh.getVertices();
//         glm::vec3 gradient;
//         outValues[0] = TriangleUtils::getSignedDistPointAndTriangle(point, trianglesData[nearestTriangleIndex], 
//                                                                     vertices[indices[3 * nearestTriangleIndex]],
//                                                                     vertices[indices[3 * nearestTriangleIndex + 1]],
//                                                                     vertices[indices[3 * nearestTriangleIndex + 2]],
//                                                                     gradient);

//         outValues[1] = gradient.x; outValues[2] = gradient.y; outValues[3] = gradient.z;
//     }

//     inline static void calculateCoefficients(const std::array<std::array<float, VALUES_PER_VERTEX>, 8>& inValues,
//                                             float nodeSize,
//                                             const std::vector<uint32_t>& triangles,
//                                             const Mesh& mesh,
//                                             const std::vector<TriangleUtils::TriangleData>& trianglesData,
//                                             std::array<float, NUM_COEFFICIENTS>& outCoeff) 
//     {
//         outCoeff[0] = 1 * inValues[0][0] + 0.0f;
//         outCoeff[1] = 1 * inValues[0][1] * nodeSize + 0.0f;
//         outCoeff[2] = -3 * inValues[0][0] + -2 * inValues[0][1] * nodeSize + 3 * inValues[1][0] + -1 * inValues[1][1] * nodeSize + 0.0f;
//         outCoeff[3] = 2 * inValues[0][0] + 1 * inValues[0][1] * nodeSize + -2 * inValues[1][0] + 1 * inValues[1][1] * nodeSize + 0.0f;
//         outCoeff[4] = 1 * inValues[0][2] * nodeSize + 0.0f;
//         outCoeff[5] = 0.0f;
//         outCoeff[6] = -3 * inValues[0][2] * nodeSize + 3 * inValues[1][2] * nodeSize + 0.0f;
//         outCoeff[7] = 2 * inValues[0][2] * nodeSize + -2 * inValues[1][2] * nodeSize + 0.0f;
//         outCoeff[8] = -3 * inValues[0][0] + -2 * inValues[0][2] * nodeSize + 3 * inValues[2][0] + -1 * inValues[2][2] * nodeSize + 0.0f;
//         outCoeff[9] = -3 * inValues[0][1] * nodeSize + 3 * inValues[2][1] * nodeSize + 0.0f;
//         outCoeff[10] = 9 * inValues[0][0] + 6 * inValues[0][1] * nodeSize + 6 * inValues[0][2] * nodeSize + -9 * inValues[1][0] + 3 * inValues[1][1] * nodeSize + -6 * inValues[1][2] * nodeSize + -9 * inValues[2][0] + -6 * inValues[2][1] * nodeSize + 3 * inValues[2][2] * nodeSize + 9 * inValues[3][0] + -3 * inValues[3][1] * nodeSize + -3 * inValues[3][2] * nodeSize + 0.0f;
//         outCoeff[11] = -6 * inValues[0][0] + -3 * inValues[0][1] * nodeSize + -4 * inValues[0][2] * nodeSize + 6 * inValues[1][0] + -3 * inValues[1][1] * nodeSize + 4 * inValues[1][2] * nodeSize + 6 * inValues[2][0] + 3 * inValues[2][1] * nodeSize + -2 * inValues[2][2] * nodeSize + -6 * inValues[3][0] + 3 * inValues[3][1] * nodeSize + 2 * inValues[3][2] * nodeSize + 0.0f;
//         outCoeff[12] = 2 * inValues[0][0] + 1 * inValues[0][2] * nodeSize + -2 * inValues[2][0] + 1 * inValues[2][2] * nodeSize + 0.0f;
//         outCoeff[13] = 2 * inValues[0][1] * nodeSize + -2 * inValues[2][1] * nodeSize + 0.0f;
//         outCoeff[14] = -6 * inValues[0][0] + -4 * inValues[0][1] * nodeSize + -3 * inValues[0][2] * nodeSize + 6 * inValues[1][0] + -2 * inValues[1][1] * nodeSize + 3 * inValues[1][2] * nodeSize + 6 * inValues[2][0] + 4 * inValues[2][1] * nodeSize + -3 * inValues[2][2] * nodeSize + -6 * inValues[3][0] + 2 * inValues[3][1] * nodeSize + 3 * inValues[3][2] * nodeSize + 0.0f;
//         outCoeff[15] = 4 * inValues[0][0] + 2 * inValues[0][1] * nodeSize + 2 * inValues[0][2] * nodeSize + -4 * inValues[1][0] + 2 * inValues[1][1] * nodeSize + -2 * inValues[1][2] * nodeSize + -4 * inValues[2][0] + -2 * inValues[2][1] * nodeSize + 2 * inValues[2][2] * nodeSize + 4 * inValues[3][0] + -2 * inValues[3][1] * nodeSize + -2 * inValues[3][2] * nodeSize + 0.0f;
//         outCoeff[16] = 1 * inValues[0][3] * nodeSize + 0.0f;
//         outCoeff[17] = 0.0f;
//         outCoeff[18] = -3 * inValues[0][3] * nodeSize + 3 * inValues[1][3] * nodeSize + 0.0f;
//         outCoeff[19] = 2 * inValues[0][3] * nodeSize + -2 * inValues[1][3] * nodeSize + 0.0f;
//         outCoeff[20] = 0.0f;
//         outCoeff[21] = 0.0f;
//         outCoeff[22] = 0.0f;
//         outCoeff[23] = 0.0f;
//         outCoeff[24] = -3 * inValues[0][3] * nodeSize + 3 * inValues[2][3] * nodeSize + 0.0f;
//         outCoeff[25] = 0.0f;
//         outCoeff[26] = 9 * inValues[0][3] * nodeSize + -9 * inValues[1][3] * nodeSize + -9 * inValues[2][3] * nodeSize + 9 * inValues[3][3] * nodeSize + 0.0f;
//         outCoeff[27] = -6 * inValues[0][3] * nodeSize + 6 * inValues[1][3] * nodeSize + 6 * inValues[2][3] * nodeSize + -6 * inValues[3][3] * nodeSize + 0.0f;
//         outCoeff[28] = 2 * inValues[0][3] * nodeSize + -2 * inValues[2][3] * nodeSize + 0.0f;
//         outCoeff[29] = 0.0f;
//         outCoeff[30] = -6 * inValues[0][3] * nodeSize + 6 * inValues[1][3] * nodeSize + 6 * inValues[2][3] * nodeSize + -6 * inValues[3][3] * nodeSize + 0.0f;
//         outCoeff[31] = 4 * inValues[0][3] * nodeSize + -4 * inValues[1][3] * nodeSize + -4 * inValues[2][3] * nodeSize + 4 * inValues[3][3] * nodeSize + 0.0f;
//         outCoeff[32] = -3 * inValues[0][0] + -2 * inValues[0][3] * nodeSize + 3 * inValues[4][0] + -1 * inValues[4][3] * nodeSize + 0.0f;
//         outCoeff[33] = -3 * inValues[0][1] * nodeSize + 3 * inValues[4][1] * nodeSize + 0.0f;
//         outCoeff[34] = 9 * inValues[0][0] + 6 * inValues[0][1] * nodeSize + 6 * inValues[0][3] * nodeSize + -9 * inValues[1][0] + 3 * inValues[1][1] * nodeSize + -6 * inValues[1][3] * nodeSize + -9 * inValues[4][0] + -6 * inValues[4][1] * nodeSize + 3 * inValues[4][3] * nodeSize + 9 * inValues[5][0] + -3 * inValues[5][1] * nodeSize + -3 * inValues[5][3] * nodeSize + 0.0f;
//         outCoeff[35] = -6 * inValues[0][0] + -3 * inValues[0][1] * nodeSize + -4 * inValues[0][3] * nodeSize + 6 * inValues[1][0] + -3 * inValues[1][1] * nodeSize + 4 * inValues[1][3] * nodeSize + 6 * inValues[4][0] + 3 * inValues[4][1] * nodeSize + -2 * inValues[4][3] * nodeSize + -6 * inValues[5][0] + 3 * inValues[5][1] * nodeSize + 2 * inValues[5][3] * nodeSize + 0.0f;
//         outCoeff[36] = -3 * inValues[0][2] * nodeSize + 3 * inValues[4][2] * nodeSize + 0.0f;
//         outCoeff[37] = 0.0f;
//         outCoeff[38] = 9 * inValues[0][2] * nodeSize + -9 * inValues[1][2] * nodeSize + -9 * inValues[4][2] * nodeSize + 9 * inValues[5][2] * nodeSize + 0.0f;
//         outCoeff[39] = -6 * inValues[0][2] * nodeSize + 6 * inValues[1][2] * nodeSize + 6 * inValues[4][2] * nodeSize + -6 * inValues[5][2] * nodeSize + 0.0f;
//         outCoeff[40] = 9 * inValues[0][0] + 6 * inValues[0][2] * nodeSize + 6 * inValues[0][3] * nodeSize + -9 * inValues[2][0] + 3 * inValues[2][2] * nodeSize + -6 * inValues[2][3] * nodeSize + -9 * inValues[4][0] + -6 * inValues[4][2] * nodeSize + 3 * inValues[4][3] * nodeSize + 9 * inValues[6][0] + -3 * inValues[6][2] * nodeSize + -3 * inValues[6][3] * nodeSize + 0.0f;
//         outCoeff[41] = 9 * inValues[0][1] * nodeSize + -9 * inValues[2][1] * nodeSize + -9 * inValues[4][1] * nodeSize + 9 * inValues[6][1] * nodeSize + 0.0f;
//         outCoeff[42] = -27 * inValues[0][0] + -18 * inValues[0][1] * nodeSize + -18 * inValues[0][2] * nodeSize + -18 * inValues[0][3] * nodeSize + 27 * inValues[1][0] + -9 * inValues[1][1] * nodeSize + 18 * inValues[1][2] * nodeSize + 18 * inValues[1][3] * nodeSize + 27 * inValues[2][0] + 18 * inValues[2][1] * nodeSize + -9 * inValues[2][2] * nodeSize + 18 * inValues[2][3] * nodeSize + -27 * inValues[3][0] + 9 * inValues[3][1] * nodeSize + 9 * inValues[3][2] * nodeSize + -18 * inValues[3][3] * nodeSize + 27 * inValues[4][0] + 18 * inValues[4][1] * nodeSize + 18 * inValues[4][2] * nodeSize + -9 * inValues[4][3] * nodeSize + -27 * inValues[5][0] + 9 * inValues[5][1] * nodeSize + -18 * inValues[5][2] * nodeSize + 9 * inValues[5][3] * nodeSize + -27 * inValues[6][0] + -18 * inValues[6][1] * nodeSize + 9 * inValues[6][2] * nodeSize + 9 * inValues[6][3] * nodeSize + 27 * inValues[7][0] + -9 * inValues[7][1] * nodeSize + -9 * inValues[7][2] * nodeSize + -9 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[43] = 18 * inValues[0][0] + 9 * inValues[0][1] * nodeSize + 12 * inValues[0][2] * nodeSize + 12 * inValues[0][3] * nodeSize + -18 * inValues[1][0] + 9 * inValues[1][1] * nodeSize + -12 * inValues[1][2] * nodeSize + -12 * inValues[1][3] * nodeSize + -18 * inValues[2][0] + -9 * inValues[2][1] * nodeSize + 6 * inValues[2][2] * nodeSize + -12 * inValues[2][3] * nodeSize + 18 * inValues[3][0] + -9 * inValues[3][1] * nodeSize + -6 * inValues[3][2] * nodeSize + 12 * inValues[3][3] * nodeSize + -18 * inValues[4][0] + -9 * inValues[4][1] * nodeSize + -12 * inValues[4][2] * nodeSize + 6 * inValues[4][3] * nodeSize + 18 * inValues[5][0] + -9 * inValues[5][1] * nodeSize + 12 * inValues[5][2] * nodeSize + -6 * inValues[5][3] * nodeSize + 18 * inValues[6][0] + 9 * inValues[6][1] * nodeSize + -6 * inValues[6][2] * nodeSize + -6 * inValues[6][3] * nodeSize + -18 * inValues[7][0] + 9 * inValues[7][1] * nodeSize + 6 * inValues[7][2] * nodeSize + 6 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[44] = -6 * inValues[0][0] + -3 * inValues[0][2] * nodeSize + -4 * inValues[0][3] * nodeSize + 6 * inValues[2][0] + -3 * inValues[2][2] * nodeSize + 4 * inValues[2][3] * nodeSize + 6 * inValues[4][0] + 3 * inValues[4][2] * nodeSize + -2 * inValues[4][3] * nodeSize + -6 * inValues[6][0] + 3 * inValues[6][2] * nodeSize + 2 * inValues[6][3] * nodeSize + 0.0f;
//         outCoeff[45] = -6 * inValues[0][1] * nodeSize + 6 * inValues[2][1] * nodeSize + 6 * inValues[4][1] * nodeSize + -6 * inValues[6][1] * nodeSize + 0.0f;
//         outCoeff[46] = 18 * inValues[0][0] + 12 * inValues[0][1] * nodeSize + 9 * inValues[0][2] * nodeSize + 12 * inValues[0][3] * nodeSize + -18 * inValues[1][0] + 6 * inValues[1][1] * nodeSize + -9 * inValues[1][2] * nodeSize + -12 * inValues[1][3] * nodeSize + -18 * inValues[2][0] + -12 * inValues[2][1] * nodeSize + 9 * inValues[2][2] * nodeSize + -12 * inValues[2][3] * nodeSize + 18 * inValues[3][0] + -6 * inValues[3][1] * nodeSize + -9 * inValues[3][2] * nodeSize + 12 * inValues[3][3] * nodeSize + -18 * inValues[4][0] + -12 * inValues[4][1] * nodeSize + -9 * inValues[4][2] * nodeSize + 6 * inValues[4][3] * nodeSize + 18 * inValues[5][0] + -6 * inValues[5][1] * nodeSize + 9 * inValues[5][2] * nodeSize + -6 * inValues[5][3] * nodeSize + 18 * inValues[6][0] + 12 * inValues[6][1] * nodeSize + -9 * inValues[6][2] * nodeSize + -6 * inValues[6][3] * nodeSize + -18 * inValues[7][0] + 6 * inValues[7][1] * nodeSize + 9 * inValues[7][2] * nodeSize + 6 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[47] = -12 * inValues[0][0] + -6 * inValues[0][1] * nodeSize + -6 * inValues[0][2] * nodeSize + -8 * inValues[0][3] * nodeSize + 12 * inValues[1][0] + -6 * inValues[1][1] * nodeSize + 6 * inValues[1][2] * nodeSize + 8 * inValues[1][3] * nodeSize + 12 * inValues[2][0] + 6 * inValues[2][1] * nodeSize + -6 * inValues[2][2] * nodeSize + 8 * inValues[2][3] * nodeSize + -12 * inValues[3][0] + 6 * inValues[3][1] * nodeSize + 6 * inValues[3][2] * nodeSize + -8 * inValues[3][3] * nodeSize + 12 * inValues[4][0] + 6 * inValues[4][1] * nodeSize + 6 * inValues[4][2] * nodeSize + -4 * inValues[4][3] * nodeSize + -12 * inValues[5][0] + 6 * inValues[5][1] * nodeSize + -6 * inValues[5][2] * nodeSize + 4 * inValues[5][3] * nodeSize + -12 * inValues[6][0] + -6 * inValues[6][1] * nodeSize + 6 * inValues[6][2] * nodeSize + 4 * inValues[6][3] * nodeSize + 12 * inValues[7][0] + -6 * inValues[7][1] * nodeSize + -6 * inValues[7][2] * nodeSize + -4 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[48] = 2 * inValues[0][0] + 1 * inValues[0][3] * nodeSize + -2 * inValues[4][0] + 1 * inValues[4][3] * nodeSize + 0.0f;
//         outCoeff[49] = 2 * inValues[0][1] * nodeSize + -2 * inValues[4][1] * nodeSize + 0.0f;
//         outCoeff[50] = -6 * inValues[0][0] + -4 * inValues[0][1] * nodeSize + -3 * inValues[0][3] * nodeSize + 6 * inValues[1][0] + -2 * inValues[1][1] * nodeSize + 3 * inValues[1][3] * nodeSize + 6 * inValues[4][0] + 4 * inValues[4][1] * nodeSize + -3 * inValues[4][3] * nodeSize + -6 * inValues[5][0] + 2 * inValues[5][1] * nodeSize + 3 * inValues[5][3] * nodeSize + 0.0f;
//         outCoeff[51] = 4 * inValues[0][0] + 2 * inValues[0][1] * nodeSize + 2 * inValues[0][3] * nodeSize + -4 * inValues[1][0] + 2 * inValues[1][1] * nodeSize + -2 * inValues[1][3] * nodeSize + -4 * inValues[4][0] + -2 * inValues[4][1] * nodeSize + 2 * inValues[4][3] * nodeSize + 4 * inValues[5][0] + -2 * inValues[5][1] * nodeSize + -2 * inValues[5][3] * nodeSize + 0.0f;
//         outCoeff[52] = 2 * inValues[0][2] * nodeSize + -2 * inValues[4][2] * nodeSize + 0.0f;
//         outCoeff[53] = 0.0f;
//         outCoeff[54] = -6 * inValues[0][2] * nodeSize + 6 * inValues[1][2] * nodeSize + 6 * inValues[4][2] * nodeSize + -6 * inValues[5][2] * nodeSize + 0.0f;
//         outCoeff[55] = 4 * inValues[0][2] * nodeSize + -4 * inValues[1][2] * nodeSize + -4 * inValues[4][2] * nodeSize + 4 * inValues[5][2] * nodeSize + 0.0f;
//         outCoeff[56] = -6 * inValues[0][0] + -4 * inValues[0][2] * nodeSize + -3 * inValues[0][3] * nodeSize + 6 * inValues[2][0] + -2 * inValues[2][2] * nodeSize + 3 * inValues[2][3] * nodeSize + 6 * inValues[4][0] + 4 * inValues[4][2] * nodeSize + -3 * inValues[4][3] * nodeSize + -6 * inValues[6][0] + 2 * inValues[6][2] * nodeSize + 3 * inValues[6][3] * nodeSize + 0.0f;
//         outCoeff[57] = -6 * inValues[0][1] * nodeSize + 6 * inValues[2][1] * nodeSize + 6 * inValues[4][1] * nodeSize + -6 * inValues[6][1] * nodeSize + 0.0f;
//         outCoeff[58] = 18 * inValues[0][0] + 12 * inValues[0][1] * nodeSize + 12 * inValues[0][2] * nodeSize + 9 * inValues[0][3] * nodeSize + -18 * inValues[1][0] + 6 * inValues[1][1] * nodeSize + -12 * inValues[1][2] * nodeSize + -9 * inValues[1][3] * nodeSize + -18 * inValues[2][0] + -12 * inValues[2][1] * nodeSize + 6 * inValues[2][2] * nodeSize + -9 * inValues[2][3] * nodeSize + 18 * inValues[3][0] + -6 * inValues[3][1] * nodeSize + -6 * inValues[3][2] * nodeSize + 9 * inValues[3][3] * nodeSize + -18 * inValues[4][0] + -12 * inValues[4][1] * nodeSize + -12 * inValues[4][2] * nodeSize + 9 * inValues[4][3] * nodeSize + 18 * inValues[5][0] + -6 * inValues[5][1] * nodeSize + 12 * inValues[5][2] * nodeSize + -9 * inValues[5][3] * nodeSize + 18 * inValues[6][0] + 12 * inValues[6][1] * nodeSize + -6 * inValues[6][2] * nodeSize + -9 * inValues[6][3] * nodeSize + -18 * inValues[7][0] + 6 * inValues[7][1] * nodeSize + 6 * inValues[7][2] * nodeSize + 9 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[59] = -12 * inValues[0][0] + -6 * inValues[0][1] * nodeSize + -8 * inValues[0][2] * nodeSize + -6 * inValues[0][3] * nodeSize + 12 * inValues[1][0] + -6 * inValues[1][1] * nodeSize + 8 * inValues[1][2] * nodeSize + 6 * inValues[1][3] * nodeSize + 12 * inValues[2][0] + 6 * inValues[2][1] * nodeSize + -4 * inValues[2][2] * nodeSize + 6 * inValues[2][3] * nodeSize + -12 * inValues[3][0] + 6 * inValues[3][1] * nodeSize + 4 * inValues[3][2] * nodeSize + -6 * inValues[3][3] * nodeSize + 12 * inValues[4][0] + 6 * inValues[4][1] * nodeSize + 8 * inValues[4][2] * nodeSize + -6 * inValues[4][3] * nodeSize + -12 * inValues[5][0] + 6 * inValues[5][1] * nodeSize + -8 * inValues[5][2] * nodeSize + 6 * inValues[5][3] * nodeSize + -12 * inValues[6][0] + -6 * inValues[6][1] * nodeSize + 4 * inValues[6][2] * nodeSize + 6 * inValues[6][3] * nodeSize + 12 * inValues[7][0] + -6 * inValues[7][1] * nodeSize + -4 * inValues[7][2] * nodeSize + -6 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[60] = 4 * inValues[0][0] + 2 * inValues[0][2] * nodeSize + 2 * inValues[0][3] * nodeSize + -4 * inValues[2][0] + 2 * inValues[2][2] * nodeSize + -2 * inValues[2][3] * nodeSize + -4 * inValues[4][0] + -2 * inValues[4][2] * nodeSize + 2 * inValues[4][3] * nodeSize + 4 * inValues[6][0] + -2 * inValues[6][2] * nodeSize + -2 * inValues[6][3] * nodeSize + 0.0f;
//         outCoeff[61] = 4 * inValues[0][1] * nodeSize + -4 * inValues[2][1] * nodeSize + -4 * inValues[4][1] * nodeSize + 4 * inValues[6][1] * nodeSize + 0.0f;
//         outCoeff[62] = -12 * inValues[0][0] + -8 * inValues[0][1] * nodeSize + -6 * inValues[0][2] * nodeSize + -6 * inValues[0][3] * nodeSize + 12 * inValues[1][0] + -4 * inValues[1][1] * nodeSize + 6 * inValues[1][2] * nodeSize + 6 * inValues[1][3] * nodeSize + 12 * inValues[2][0] + 8 * inValues[2][1] * nodeSize + -6 * inValues[2][2] * nodeSize + 6 * inValues[2][3] * nodeSize + -12 * inValues[3][0] + 4 * inValues[3][1] * nodeSize + 6 * inValues[3][2] * nodeSize + -6 * inValues[3][3] * nodeSize + 12 * inValues[4][0] + 8 * inValues[4][1] * nodeSize + 6 * inValues[4][2] * nodeSize + -6 * inValues[4][3] * nodeSize + -12 * inValues[5][0] + 4 * inValues[5][1] * nodeSize + -6 * inValues[5][2] * nodeSize + 6 * inValues[5][3] * nodeSize + -12 * inValues[6][0] + -8 * inValues[6][1] * nodeSize + 6 * inValues[6][2] * nodeSize + 6 * inValues[6][3] * nodeSize + 12 * inValues[7][0] + -4 * inValues[7][1] * nodeSize + -6 * inValues[7][2] * nodeSize + -6 * inValues[7][3] * nodeSize + 0.0f;
//         outCoeff[63] = 8 * inValues[0][0] + 4 * inValues[0][1] * nodeSize + 4 * inValues[0][2] * nodeSize + 4 * inValues[0][3] * nodeSize + -8 * inValues[1][0] + 4 * inValues[1][1] * nodeSize + -4 * inValues[1][2] * nodeSize + -4 * inValues[1][3] * nodeSize + -8 * inValues[2][0] + -4 * inValues[2][1] * nodeSize + 4 * inValues[2][2] * nodeSize + -4 * inValues[2][3] * nodeSize + 8 * inValues[3][0] + -4 * inValues[3][1] * nodeSize + -4 * inValues[3][2] * nodeSize + 4 * inValues[3][3] * nodeSize + -8 * inValues[4][0] + -4 * inValues[4][1] * nodeSize + -4 * inValues[4][2] * nodeSize + 4 * inValues[4][3] * nodeSize + 8 * inValues[5][0] + -4 * inValues[5][1] * nodeSize + 4 * inValues[5][2] * nodeSize + -4 * inValues[5][3] * nodeSize + 8 * inValues[6][0] + 4 * inValues[6][1] * nodeSize + -4 * inValues[6][2] * nodeSize + -4 * inValues[6][3] * nodeSize + -8 * inValues[7][0] + 4 * inValues[7][1] * nodeSize + 4 * inValues[7][2] * nodeSize + 4 * inValues[7][3] * nodeSize + 0.0f;
//     }

//     inline static void interpolateVertexValues(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart, float nodeSize, std::array<float, VALUES_PER_VERTEX>& outValues)
//     {
//         outValues[0] = 0.0f
//          + values[0] + values[1] * fracPart[0] + values[2] * fracPart[0] * fracPart[0] + values[3] * fracPart[0] * fracPart[0] * fracPart[0] + values[4] * fracPart[1] + values[5] * fracPart[0] * fracPart[1] + values[6] * fracPart[0] * fracPart[0] * fracPart[1] + values[7] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + values[8] * fracPart[1] * fracPart[1] + values[9] * fracPart[0] * fracPart[1] * fracPart[1] + values[10] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[12] * fracPart[1] * fracPart[1] * fracPart[1] + values[13] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
//          + values[16] * fracPart[2] + values[17] * fracPart[0] * fracPart[2] + values[18] * fracPart[0] * fracPart[0] * fracPart[2] + values[19] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + values[20] * fracPart[1] * fracPart[2] + values[21] * fracPart[0] * fracPart[1] * fracPart[2] + values[22] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[24] * fracPart[1] * fracPart[1] * fracPart[2] + values[25] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[28] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
//          + values[32] * fracPart[2] * fracPart[2] + values[33] * fracPart[0] * fracPart[2] * fracPart[2] + values[34] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[36] * fracPart[1] * fracPart[2] * fracPart[2] + values[37] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[40] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
//          + values[48] * fracPart[2] * fracPart[2] * fracPart[2] + values[49] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[52] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2];

//         outValues[1] = (1 * values[1] + 2 * values[2] * fracPart[0] + 3 * values[3] * fracPart[0] * fracPart[0] + 1 * values[5] * fracPart[1] + 2 * values[6] * fracPart[0] * fracPart[1] + 3 * values[7] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[9] * fracPart[1] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[11] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[13] * fracPart[1] * fracPart[1] * fracPart[1] + 2 * values[14] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
//          + 1 * values[17] * fracPart[2] + 2 * values[18] * fracPart[0] * fracPart[2] + 3 * values[19] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[21] * fracPart[1] * fracPart[2] + 2 * values[22] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[23] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 1 * values[25] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 1 * values[29] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
//          + 1 * values[33] * fracPart[2] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[35] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[39] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[41] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[45] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
//          + 1 * values[49] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[50] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[54] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[57] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[61] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2]) / nodeSize;


//         outValues[2] = (1 * values[4] + 1 * values[5] * fracPart[0] + 1 * values[6] * fracPart[0] * fracPart[0] + 1 * values[7] * fracPart[0] * fracPart[0] * fracPart[0] + 2 * values[8] * fracPart[1] + 2 * values[9] * fracPart[0] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[0] * fracPart[1] + 2 * values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[12] * fracPart[1] * fracPart[1] + 3 * values[13] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
//          + 1 * values[20] * fracPart[2] + 1 * values[21] * fracPart[0] * fracPart[2] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[24] * fracPart[1] * fracPart[2] + 2 * values[25] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[28] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
//          + 1 * values[36] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[38] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[44] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
//          + 1 * values[52] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[54] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[56] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[57] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2]) / nodeSize;

//         outValues[3] = (1 * values[16] + 1 * values[17] * fracPart[0] + 1 * values[18] * fracPart[0] * fracPart[0] + 1 * values[19] * fracPart[0] * fracPart[0] * fracPart[0] + 1 * values[20] * fracPart[1] + 1 * values[21] * fracPart[0] * fracPart[1] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[24] * fracPart[1] * fracPart[1] + 1 * values[25] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[28] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
//          + 2 * values[32] * fracPart[2] + 2 * values[33] * fracPart[0] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[36] * fracPart[1] * fracPart[2] + 2 * values[37] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
//          + 3 * values[48] * fracPart[2] * fracPart[2] + 3 * values[49] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[52] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]) / nodeSize;
//     }
// };

struct TriCubicInterpolation
{
    static constexpr uint32_t VALUES_PER_VERTEX = 8;
    static constexpr uint32_t EXTRA_VALUES = 0;
    static constexpr uint32_t NUM_COEFFICIENTS = 64;

    inline static void calculatePointValues(glm::vec3 point,
                                      uint32_t nearestTriangleIndex,
                                      const Mesh& mesh,
                                      const std::vector<TriangleUtils::TriangleData>& trianglesData, 
                                      std::array<float, VALUES_PER_VERTEX>& outValues)
    {
        const std::vector<uint32_t>& indices = mesh.getIndices();
        const std::vector<glm::vec3>& vertices = mesh.getVertices();
        glm::vec3 gradient;
        outValues[0] = TriangleUtils::getSignedDistPointAndTriangle(point, trianglesData[nearestTriangleIndex], 
                                                                    vertices[indices[3 * nearestTriangleIndex]],
                                                                    vertices[indices[3 * nearestTriangleIndex + 1]],
                                                                    vertices[indices[3 * nearestTriangleIndex + 2]],
                                                                    gradient);

        outValues[1] = gradient.x; outValues[2] = gradient.y; outValues[3] = gradient.z;
        outValues[4] = 0.0f; outValues[5] = 0.0f; outValues[6] = 0.0f; outValues[7] = 0.0f;
    }

    inline static void calculateCoefficients(const std::array<std::array<float, VALUES_PER_VERTEX>, 8>& inputInValues,
                                            float nodeSize,
                                            const std::vector<uint32_t>& triangles,
                                            const Mesh& mesh,
                                            const std::vector<TriangleUtils::TriangleData>& trianglesData,
                                            std::array<float, NUM_COEFFICIENTS>& outCoeff) 
    {
        std::array<std::array<float, VALUES_PER_VERTEX>, 8> inValues = inputInValues;
        
        for(uint32_t i=0; i < 8; i++)
        {
            inValues[i][1] *= nodeSize;
            inValues[i][2] *= nodeSize;
            inValues[i][3] *= nodeSize;

            const float sqNodeSize = nodeSize * nodeSize;
            inValues[i][4] *= sqNodeSize;
            inValues[i][5] *= sqNodeSize;
            inValues[i][6] *= sqNodeSize;
            inValues[i][7] *= sqNodeSize * nodeSize;
        }

        outCoeff[0] = 1 * inValues[0][0];
        outCoeff[1] = 1 * inValues[0][1];
        outCoeff[2] = -3 * inValues[0][0] + -2 * inValues[0][1] + 3 * inValues[1][0] + -1 * inValues[1][1];
        outCoeff[3] = 2 * inValues[0][0] + 1 * inValues[0][1] + -2 * inValues[1][0] + 1 * inValues[1][1];
        outCoeff[4] = 1 * inValues[0][2];
        outCoeff[5] = 1 * inValues[0][4];
        outCoeff[6] = -3 * inValues[0][2] + -2 * inValues[0][4] + 3 * inValues[1][2] + -1 * inValues[1][4];
        outCoeff[7] = 2 * inValues[0][2] + 1 * inValues[0][4] + -2 * inValues[1][2] + 1 * inValues[1][4];
        outCoeff[8] = -3 * inValues[0][0] + -2 * inValues[0][2] + 3 * inValues[2][0] + -1 * inValues[2][2];
        outCoeff[9] = -3 * inValues[0][1] + -2 * inValues[0][4] + 3 * inValues[2][1] + -1 * inValues[2][4];
        outCoeff[10] = 9 * inValues[0][0] + 6 * inValues[0][1] + 6 * inValues[0][2] + 4 * inValues[0][4] + -9 * inValues[1][0] + 3 * inValues[1][1] + -6 * inValues[1][2] + 2 * inValues[1][4] + -9 * inValues[2][0] + -6 * inValues[2][1] + 3 * inValues[2][2] + 2 * inValues[2][4] + 9 * inValues[3][0] + -3 * inValues[3][1] + -3 * inValues[3][2] + 1 * inValues[3][4];
        outCoeff[11] = -6 * inValues[0][0] + -3 * inValues[0][1] + -4 * inValues[0][2] + -2 * inValues[0][4] + 6 * inValues[1][0] + -3 * inValues[1][1] + 4 * inValues[1][2] + -2 * inValues[1][4] + 6 * inValues[2][0] + 3 * inValues[2][1] + -2 * inValues[2][2] + -1 * inValues[2][4] + -6 * inValues[3][0] + 3 * inValues[3][1] + 2 * inValues[3][2] + -1 * inValues[3][4];
        outCoeff[12] = 2 * inValues[0][0] + 1 * inValues[0][2] + -2 * inValues[2][0] + 1 * inValues[2][2];
        outCoeff[13] = 2 * inValues[0][1] + 1 * inValues[0][4] + -2 * inValues[2][1] + 1 * inValues[2][4];
        outCoeff[14] = -6 * inValues[0][0] + -4 * inValues[0][1] + -3 * inValues[0][2] + -2 * inValues[0][4] + 6 * inValues[1][0] + -2 * inValues[1][1] + 3 * inValues[1][2] + -1 * inValues[1][4] + 6 * inValues[2][0] + 4 * inValues[2][1] + -3 * inValues[2][2] + -2 * inValues[2][4] + -6 * inValues[3][0] + 2 * inValues[3][1] + 3 * inValues[3][2] + -1 * inValues[3][4];
        outCoeff[15] = 4 * inValues[0][0] + 2 * inValues[0][1] + 2 * inValues[0][2] + 1 * inValues[0][4] + -4 * inValues[1][0] + 2 * inValues[1][1] + -2 * inValues[1][2] + 1 * inValues[1][4] + -4 * inValues[2][0] + -2 * inValues[2][1] + 2 * inValues[2][2] + 1 * inValues[2][4] + 4 * inValues[3][0] + -2 * inValues[3][1] + -2 * inValues[3][2] + 1 * inValues[3][4];
        outCoeff[16] = 1 * inValues[0][3];
        outCoeff[17] = 1 * inValues[0][5];
        outCoeff[18] = -3 * inValues[0][3] + -2 * inValues[0][5] + 3 * inValues[1][3] + -1 * inValues[1][5];
        outCoeff[19] = 2 * inValues[0][3] + 1 * inValues[0][5] + -2 * inValues[1][3] + 1 * inValues[1][5];
        outCoeff[20] = 1 * inValues[0][6];
        outCoeff[21] = 1 * inValues[0][7];
        outCoeff[22] = -3 * inValues[0][6] + -2 * inValues[0][7] + 3 * inValues[1][6] + -1 * inValues[1][7];
        outCoeff[23] = 2 * inValues[0][6] + 1 * inValues[0][7] + -2 * inValues[1][6] + 1 * inValues[1][7];
        outCoeff[24] = -3 * inValues[0][3] + -2 * inValues[0][6] + 3 * inValues[2][3] + -1 * inValues[2][6];
        outCoeff[25] = -3 * inValues[0][5] + -2 * inValues[0][7] + 3 * inValues[2][5] + -1 * inValues[2][7];
        outCoeff[26] = 9 * inValues[0][3] + 6 * inValues[0][5] + 6 * inValues[0][6] + 4 * inValues[0][7] + -9 * inValues[1][3] + 3 * inValues[1][5] + -6 * inValues[1][6] + 2 * inValues[1][7] + -9 * inValues[2][3] + -6 * inValues[2][5] + 3 * inValues[2][6] + 2 * inValues[2][7] + 9 * inValues[3][3] + -3 * inValues[3][5] + -3 * inValues[3][6] + 1 * inValues[3][7];
        outCoeff[27] = -6 * inValues[0][3] + -3 * inValues[0][5] + -4 * inValues[0][6] + -2 * inValues[0][7] + 6 * inValues[1][3] + -3 * inValues[1][5] + 4 * inValues[1][6] + -2 * inValues[1][7] + 6 * inValues[2][3] + 3 * inValues[2][5] + -2 * inValues[2][6] + -1 * inValues[2][7] + -6 * inValues[3][3] + 3 * inValues[3][5] + 2 * inValues[3][6] + -1 * inValues[3][7];
        outCoeff[28] = 2 * inValues[0][3] + 1 * inValues[0][6] + -2 * inValues[2][3] + 1 * inValues[2][6];
        outCoeff[29] = 2 * inValues[0][5] + 1 * inValues[0][7] + -2 * inValues[2][5] + 1 * inValues[2][7];
        outCoeff[30] = -6 * inValues[0][3] + -4 * inValues[0][5] + -3 * inValues[0][6] + -2 * inValues[0][7] + 6 * inValues[1][3] + -2 * inValues[1][5] + 3 * inValues[1][6] + -1 * inValues[1][7] + 6 * inValues[2][3] + 4 * inValues[2][5] + -3 * inValues[2][6] + -2 * inValues[2][7] + -6 * inValues[3][3] + 2 * inValues[3][5] + 3 * inValues[3][6] + -1 * inValues[3][7];
        outCoeff[31] = 4 * inValues[0][3] + 2 * inValues[0][5] + 2 * inValues[0][6] + 1 * inValues[0][7] + -4 * inValues[1][3] + 2 * inValues[1][5] + -2 * inValues[1][6] + 1 * inValues[1][7] + -4 * inValues[2][3] + -2 * inValues[2][5] + 2 * inValues[2][6] + 1 * inValues[2][7] + 4 * inValues[3][3] + -2 * inValues[3][5] + -2 * inValues[3][6] + 1 * inValues[3][7];
        outCoeff[32] = -3 * inValues[0][0] + -2 * inValues[0][3] + 3 * inValues[4][0] + -1 * inValues[4][3];
        outCoeff[33] = -3 * inValues[0][1] + -2 * inValues[0][5] + 3 * inValues[4][1] + -1 * inValues[4][5];
        outCoeff[34] = 9 * inValues[0][0] + 6 * inValues[0][1] + 6 * inValues[0][3] + 4 * inValues[0][5] + -9 * inValues[1][0] + 3 * inValues[1][1] + -6 * inValues[1][3] + 2 * inValues[1][5] + -9 * inValues[4][0] + -6 * inValues[4][1] + 3 * inValues[4][3] + 2 * inValues[4][5] + 9 * inValues[5][0] + -3 * inValues[5][1] + -3 * inValues[5][3] + 1 * inValues[5][5];
        outCoeff[35] = -6 * inValues[0][0] + -3 * inValues[0][1] + -4 * inValues[0][3] + -2 * inValues[0][5] + 6 * inValues[1][0] + -3 * inValues[1][1] + 4 * inValues[1][3] + -2 * inValues[1][5] + 6 * inValues[4][0] + 3 * inValues[4][1] + -2 * inValues[4][3] + -1 * inValues[4][5] + -6 * inValues[5][0] + 3 * inValues[5][1] + 2 * inValues[5][3] + -1 * inValues[5][5];
        outCoeff[36] = -3 * inValues[0][2] + -2 * inValues[0][6] + 3 * inValues[4][2] + -1 * inValues[4][6];
        outCoeff[37] = -3 * inValues[0][4] + -2 * inValues[0][7] + 3 * inValues[4][4] + -1 * inValues[4][7];
        outCoeff[38] = 9 * inValues[0][2] + 6 * inValues[0][4] + 6 * inValues[0][6] + 4 * inValues[0][7] + -9 * inValues[1][2] + 3 * inValues[1][4] + -6 * inValues[1][6] + 2 * inValues[1][7] + -9 * inValues[4][2] + -6 * inValues[4][4] + 3 * inValues[4][6] + 2 * inValues[4][7] + 9 * inValues[5][2] + -3 * inValues[5][4] + -3 * inValues[5][6] + 1 * inValues[5][7];
        outCoeff[39] = -6 * inValues[0][2] + -3 * inValues[0][4] + -4 * inValues[0][6] + -2 * inValues[0][7] + 6 * inValues[1][2] + -3 * inValues[1][4] + 4 * inValues[1][6] + -2 * inValues[1][7] + 6 * inValues[4][2] + 3 * inValues[4][4] + -2 * inValues[4][6] + -1 * inValues[4][7] + -6 * inValues[5][2] + 3 * inValues[5][4] + 2 * inValues[5][6] + -1 * inValues[5][7];
        outCoeff[40] = 9 * inValues[0][0] + 6 * inValues[0][2] + 6 * inValues[0][3] + 4 * inValues[0][6] + -9 * inValues[2][0] + 3 * inValues[2][2] + -6 * inValues[2][3] + 2 * inValues[2][6] + -9 * inValues[4][0] + -6 * inValues[4][2] + 3 * inValues[4][3] + 2 * inValues[4][6] + 9 * inValues[6][0] + -3 * inValues[6][2] + -3 * inValues[6][3] + 1 * inValues[6][6];
        outCoeff[41] = 9 * inValues[0][1] + 6 * inValues[0][4] + 6 * inValues[0][5] + 4 * inValues[0][7] + -9 * inValues[2][1] + 3 * inValues[2][4] + -6 * inValues[2][5] + 2 * inValues[2][7] + -9 * inValues[4][1] + -6 * inValues[4][4] + 3 * inValues[4][5] + 2 * inValues[4][7] + 9 * inValues[6][1] + -3 * inValues[6][4] + -3 * inValues[6][5] + 1 * inValues[6][7];
        outCoeff[42] = -27 * inValues[0][0] + -18 * inValues[0][1] + -18 * inValues[0][2] + -18 * inValues[0][3] + -12 * inValues[0][4] + -12 * inValues[0][5] + -12 * inValues[0][6] + -8 * inValues[0][7] + 27 * inValues[1][0] + -9 * inValues[1][1] + 18 * inValues[1][2] + 18 * inValues[1][3] + -6 * inValues[1][4] + -6 * inValues[1][5] + 12 * inValues[1][6] + -4 * inValues[1][7] + 27 * inValues[2][0] + 18 * inValues[2][1] + -9 * inValues[2][2] + 18 * inValues[2][3] + -6 * inValues[2][4] + 12 * inValues[2][5] + -6 * inValues[2][6] + -4 * inValues[2][7] + -27 * inValues[3][0] + 9 * inValues[3][1] + 9 * inValues[3][2] + -18 * inValues[3][3] + -3 * inValues[3][4] + 6 * inValues[3][5] + 6 * inValues[3][6] + -2 * inValues[3][7] + 27 * inValues[4][0] + 18 * inValues[4][1] + 18 * inValues[4][2] + -9 * inValues[4][3] + 12 * inValues[4][4] + -6 * inValues[4][5] + -6 * inValues[4][6] + -4 * inValues[4][7] + -27 * inValues[5][0] + 9 * inValues[5][1] + -18 * inValues[5][2] + 9 * inValues[5][3] + 6 * inValues[5][4] + -3 * inValues[5][5] + 6 * inValues[5][6] + -2 * inValues[5][7] + -27 * inValues[6][0] + -18 * inValues[6][1] + 9 * inValues[6][2] + 9 * inValues[6][3] + 6 * inValues[6][4] + 6 * inValues[6][5] + -3 * inValues[6][6] + -2 * inValues[6][7] + 27 * inValues[7][0] + -9 * inValues[7][1] + -9 * inValues[7][2] + -9 * inValues[7][3] + 3 * inValues[7][4] + 3 * inValues[7][5] + 3 * inValues[7][6] + -1 * inValues[7][7];
        outCoeff[43] = 18 * inValues[0][0] + 9 * inValues[0][1] + 12 * inValues[0][2] + 12 * inValues[0][3] + 6 * inValues[0][4] + 6 * inValues[0][5] + 8 * inValues[0][6] + 4 * inValues[0][7] + -18 * inValues[1][0] + 9 * inValues[1][1] + -12 * inValues[1][2] + -12 * inValues[1][3] + 6 * inValues[1][4] + 6 * inValues[1][5] + -8 * inValues[1][6] + 4 * inValues[1][7] + -18 * inValues[2][0] + -9 * inValues[2][1] + 6 * inValues[2][2] + -12 * inValues[2][3] + 3 * inValues[2][4] + -6 * inValues[2][5] + 4 * inValues[2][6] + 2 * inValues[2][7] + 18 * inValues[3][0] + -9 * inValues[3][1] + -6 * inValues[3][2] + 12 * inValues[3][3] + 3 * inValues[3][4] + -6 * inValues[3][5] + -4 * inValues[3][6] + 2 * inValues[3][7] + -18 * inValues[4][0] + -9 * inValues[4][1] + -12 * inValues[4][2] + 6 * inValues[4][3] + -6 * inValues[4][4] + 3 * inValues[4][5] + 4 * inValues[4][6] + 2 * inValues[4][7] + 18 * inValues[5][0] + -9 * inValues[5][1] + 12 * inValues[5][2] + -6 * inValues[5][3] + -6 * inValues[5][4] + 3 * inValues[5][5] + -4 * inValues[5][6] + 2 * inValues[5][7] + 18 * inValues[6][0] + 9 * inValues[6][1] + -6 * inValues[6][2] + -6 * inValues[6][3] + -3 * inValues[6][4] + -3 * inValues[6][5] + 2 * inValues[6][6] + 1 * inValues[6][7] + -18 * inValues[7][0] + 9 * inValues[7][1] + 6 * inValues[7][2] + 6 * inValues[7][3] + -3 * inValues[7][4] + -3 * inValues[7][5] + -2 * inValues[7][6] + 1 * inValues[7][7];
        outCoeff[44] = -6 * inValues[0][0] + -3 * inValues[0][2] + -4 * inValues[0][3] + -2 * inValues[0][6] + 6 * inValues[2][0] + -3 * inValues[2][2] + 4 * inValues[2][3] + -2 * inValues[2][6] + 6 * inValues[4][0] + 3 * inValues[4][2] + -2 * inValues[4][3] + -1 * inValues[4][6] + -6 * inValues[6][0] + 3 * inValues[6][2] + 2 * inValues[6][3] + -1 * inValues[6][6];
        outCoeff[45] = -6 * inValues[0][1] + -3 * inValues[0][4] + -4 * inValues[0][5] + -2 * inValues[0][7] + 6 * inValues[2][1] + -3 * inValues[2][4] + 4 * inValues[2][5] + -2 * inValues[2][7] + 6 * inValues[4][1] + 3 * inValues[4][4] + -2 * inValues[4][5] + -1 * inValues[4][7] + -6 * inValues[6][1] + 3 * inValues[6][4] + 2 * inValues[6][5] + -1 * inValues[6][7];
        outCoeff[46] = 18 * inValues[0][0] + 12 * inValues[0][1] + 9 * inValues[0][2] + 12 * inValues[0][3] + 6 * inValues[0][4] + 8 * inValues[0][5] + 6 * inValues[0][6] + 4 * inValues[0][7] + -18 * inValues[1][0] + 6 * inValues[1][1] + -9 * inValues[1][2] + -12 * inValues[1][3] + 3 * inValues[1][4] + 4 * inValues[1][5] + -6 * inValues[1][6] + 2 * inValues[1][7] + -18 * inValues[2][0] + -12 * inValues[2][1] + 9 * inValues[2][2] + -12 * inValues[2][3] + 6 * inValues[2][4] + -8 * inValues[2][5] + 6 * inValues[2][6] + 4 * inValues[2][7] + 18 * inValues[3][0] + -6 * inValues[3][1] + -9 * inValues[3][2] + 12 * inValues[3][3] + 3 * inValues[3][4] + -4 * inValues[3][5] + -6 * inValues[3][6] + 2 * inValues[3][7] + -18 * inValues[4][0] + -12 * inValues[4][1] + -9 * inValues[4][2] + 6 * inValues[4][3] + -6 * inValues[4][4] + 4 * inValues[4][5] + 3 * inValues[4][6] + 2 * inValues[4][7] + 18 * inValues[5][0] + -6 * inValues[5][1] + 9 * inValues[5][2] + -6 * inValues[5][3] + -3 * inValues[5][4] + 2 * inValues[5][5] + -3 * inValues[5][6] + 1 * inValues[5][7] + 18 * inValues[6][0] + 12 * inValues[6][1] + -9 * inValues[6][2] + -6 * inValues[6][3] + -6 * inValues[6][4] + -4 * inValues[6][5] + 3 * inValues[6][6] + 2 * inValues[6][7] + -18 * inValues[7][0] + 6 * inValues[7][1] + 9 * inValues[7][2] + 6 * inValues[7][3] + -3 * inValues[7][4] + -2 * inValues[7][5] + -3 * inValues[7][6] + 1 * inValues[7][7];
        outCoeff[47] = -12 * inValues[0][0] + -6 * inValues[0][1] + -6 * inValues[0][2] + -8 * inValues[0][3] + -3 * inValues[0][4] + -4 * inValues[0][5] + -4 * inValues[0][6] + -2 * inValues[0][7] + 12 * inValues[1][0] + -6 * inValues[1][1] + 6 * inValues[1][2] + 8 * inValues[1][3] + -3 * inValues[1][4] + -4 * inValues[1][5] + 4 * inValues[1][6] + -2 * inValues[1][7] + 12 * inValues[2][0] + 6 * inValues[2][1] + -6 * inValues[2][2] + 8 * inValues[2][3] + -3 * inValues[2][4] + 4 * inValues[2][5] + -4 * inValues[2][6] + -2 * inValues[2][7] + -12 * inValues[3][0] + 6 * inValues[3][1] + 6 * inValues[3][2] + -8 * inValues[3][3] + -3 * inValues[3][4] + 4 * inValues[3][5] + 4 * inValues[3][6] + -2 * inValues[3][7] + 12 * inValues[4][0] + 6 * inValues[4][1] + 6 * inValues[4][2] + -4 * inValues[4][3] + 3 * inValues[4][4] + -2 * inValues[4][5] + -2 * inValues[4][6] + -1 * inValues[4][7] + -12 * inValues[5][0] + 6 * inValues[5][1] + -6 * inValues[5][2] + 4 * inValues[5][3] + 3 * inValues[5][4] + -2 * inValues[5][5] + 2 * inValues[5][6] + -1 * inValues[5][7] + -12 * inValues[6][0] + -6 * inValues[6][1] + 6 * inValues[6][2] + 4 * inValues[6][3] + 3 * inValues[6][4] + 2 * inValues[6][5] + -2 * inValues[6][6] + -1 * inValues[6][7] + 12 * inValues[7][0] + -6 * inValues[7][1] + -6 * inValues[7][2] + -4 * inValues[7][3] + 3 * inValues[7][4] + 2 * inValues[7][5] + 2 * inValues[7][6] + -1 * inValues[7][7];
        outCoeff[48] = 2 * inValues[0][0] + 1 * inValues[0][3] + -2 * inValues[4][0] + 1 * inValues[4][3];
        outCoeff[49] = 2 * inValues[0][1] + 1 * inValues[0][5] + -2 * inValues[4][1] + 1 * inValues[4][5];
        outCoeff[50] = -6 * inValues[0][0] + -4 * inValues[0][1] + -3 * inValues[0][3] + -2 * inValues[0][5] + 6 * inValues[1][0] + -2 * inValues[1][1] + 3 * inValues[1][3] + -1 * inValues[1][5] + 6 * inValues[4][0] + 4 * inValues[4][1] + -3 * inValues[4][3] + -2 * inValues[4][5] + -6 * inValues[5][0] + 2 * inValues[5][1] + 3 * inValues[5][3] + -1 * inValues[5][5];
        outCoeff[51] = 4 * inValues[0][0] + 2 * inValues[0][1] + 2 * inValues[0][3] + 1 * inValues[0][5] + -4 * inValues[1][0] + 2 * inValues[1][1] + -2 * inValues[1][3] + 1 * inValues[1][5] + -4 * inValues[4][0] + -2 * inValues[4][1] + 2 * inValues[4][3] + 1 * inValues[4][5] + 4 * inValues[5][0] + -2 * inValues[5][1] + -2 * inValues[5][3] + 1 * inValues[5][5];
        outCoeff[52] = 2 * inValues[0][2] + 1 * inValues[0][6] + -2 * inValues[4][2] + 1 * inValues[4][6];
        outCoeff[53] = 2 * inValues[0][4] + 1 * inValues[0][7] + -2 * inValues[4][4] + 1 * inValues[4][7];
        outCoeff[54] = -6 * inValues[0][2] + -4 * inValues[0][4] + -3 * inValues[0][6] + -2 * inValues[0][7] + 6 * inValues[1][2] + -2 * inValues[1][4] + 3 * inValues[1][6] + -1 * inValues[1][7] + 6 * inValues[4][2] + 4 * inValues[4][4] + -3 * inValues[4][6] + -2 * inValues[4][7] + -6 * inValues[5][2] + 2 * inValues[5][4] + 3 * inValues[5][6] + -1 * inValues[5][7];
        outCoeff[55] = 4 * inValues[0][2] + 2 * inValues[0][4] + 2 * inValues[0][6] + 1 * inValues[0][7] + -4 * inValues[1][2] + 2 * inValues[1][4] + -2 * inValues[1][6] + 1 * inValues[1][7] + -4 * inValues[4][2] + -2 * inValues[4][4] + 2 * inValues[4][6] + 1 * inValues[4][7] + 4 * inValues[5][2] + -2 * inValues[5][4] + -2 * inValues[5][6] + 1 * inValues[5][7];
        outCoeff[56] = -6 * inValues[0][0] + -4 * inValues[0][2] + -3 * inValues[0][3] + -2 * inValues[0][6] + 6 * inValues[2][0] + -2 * inValues[2][2] + 3 * inValues[2][3] + -1 * inValues[2][6] + 6 * inValues[4][0] + 4 * inValues[4][2] + -3 * inValues[4][3] + -2 * inValues[4][6] + -6 * inValues[6][0] + 2 * inValues[6][2] + 3 * inValues[6][3] + -1 * inValues[6][6];
        outCoeff[57] = -6 * inValues[0][1] + -4 * inValues[0][4] + -3 * inValues[0][5] + -2 * inValues[0][7] + 6 * inValues[2][1] + -2 * inValues[2][4] + 3 * inValues[2][5] + -1 * inValues[2][7] + 6 * inValues[4][1] + 4 * inValues[4][4] + -3 * inValues[4][5] + -2 * inValues[4][7] + -6 * inValues[6][1] + 2 * inValues[6][4] + 3 * inValues[6][5] + -1 * inValues[6][7];
        outCoeff[58] = 18 * inValues[0][0] + 12 * inValues[0][1] + 12 * inValues[0][2] + 9 * inValues[0][3] + 8 * inValues[0][4] + 6 * inValues[0][5] + 6 * inValues[0][6] + 4 * inValues[0][7] + -18 * inValues[1][0] + 6 * inValues[1][1] + -12 * inValues[1][2] + -9 * inValues[1][3] + 4 * inValues[1][4] + 3 * inValues[1][5] + -6 * inValues[1][6] + 2 * inValues[1][7] + -18 * inValues[2][0] + -12 * inValues[2][1] + 6 * inValues[2][2] + -9 * inValues[2][3] + 4 * inValues[2][4] + -6 * inValues[2][5] + 3 * inValues[2][6] + 2 * inValues[2][7] + 18 * inValues[3][0] + -6 * inValues[3][1] + -6 * inValues[3][2] + 9 * inValues[3][3] + 2 * inValues[3][4] + -3 * inValues[3][5] + -3 * inValues[3][6] + 1 * inValues[3][7] + -18 * inValues[4][0] + -12 * inValues[4][1] + -12 * inValues[4][2] + 9 * inValues[4][3] + -8 * inValues[4][4] + 6 * inValues[4][5] + 6 * inValues[4][6] + 4 * inValues[4][7] + 18 * inValues[5][0] + -6 * inValues[5][1] + 12 * inValues[5][2] + -9 * inValues[5][3] + -4 * inValues[5][4] + 3 * inValues[5][5] + -6 * inValues[5][6] + 2 * inValues[5][7] + 18 * inValues[6][0] + 12 * inValues[6][1] + -6 * inValues[6][2] + -9 * inValues[6][3] + -4 * inValues[6][4] + -6 * inValues[6][5] + 3 * inValues[6][6] + 2 * inValues[6][7] + -18 * inValues[7][0] + 6 * inValues[7][1] + 6 * inValues[7][2] + 9 * inValues[7][3] + -2 * inValues[7][4] + -3 * inValues[7][5] + -3 * inValues[7][6] + 1 * inValues[7][7];
        outCoeff[59] = -12 * inValues[0][0] + -6 * inValues[0][1] + -8 * inValues[0][2] + -6 * inValues[0][3] + -4 * inValues[0][4] + -3 * inValues[0][5] + -4 * inValues[0][6] + -2 * inValues[0][7] + 12 * inValues[1][0] + -6 * inValues[1][1] + 8 * inValues[1][2] + 6 * inValues[1][3] + -4 * inValues[1][4] + -3 * inValues[1][5] + 4 * inValues[1][6] + -2 * inValues[1][7] + 12 * inValues[2][0] + 6 * inValues[2][1] + -4 * inValues[2][2] + 6 * inValues[2][3] + -2 * inValues[2][4] + 3 * inValues[2][5] + -2 * inValues[2][6] + -1 * inValues[2][7] + -12 * inValues[3][0] + 6 * inValues[3][1] + 4 * inValues[3][2] + -6 * inValues[3][3] + -2 * inValues[3][4] + 3 * inValues[3][5] + 2 * inValues[3][6] + -1 * inValues[3][7] + 12 * inValues[4][0] + 6 * inValues[4][1] + 8 * inValues[4][2] + -6 * inValues[4][3] + 4 * inValues[4][4] + -3 * inValues[4][5] + -4 * inValues[4][6] + -2 * inValues[4][7] + -12 * inValues[5][0] + 6 * inValues[5][1] + -8 * inValues[5][2] + 6 * inValues[5][3] + 4 * inValues[5][4] + -3 * inValues[5][5] + 4 * inValues[5][6] + -2 * inValues[5][7] + -12 * inValues[6][0] + -6 * inValues[6][1] + 4 * inValues[6][2] + 6 * inValues[6][3] + 2 * inValues[6][4] + 3 * inValues[6][5] + -2 * inValues[6][6] + -1 * inValues[6][7] + 12 * inValues[7][0] + -6 * inValues[7][1] + -4 * inValues[7][2] + -6 * inValues[7][3] + 2 * inValues[7][4] + 3 * inValues[7][5] + 2 * inValues[7][6] + -1 * inValues[7][7];
        outCoeff[60] = 4 * inValues[0][0] + 2 * inValues[0][2] + 2 * inValues[0][3] + 1 * inValues[0][6] + -4 * inValues[2][0] + 2 * inValues[2][2] + -2 * inValues[2][3] + 1 * inValues[2][6] + -4 * inValues[4][0] + -2 * inValues[4][2] + 2 * inValues[4][3] + 1 * inValues[4][6] + 4 * inValues[6][0] + -2 * inValues[6][2] + -2 * inValues[6][3] + 1 * inValues[6][6];
        outCoeff[61] = 4 * inValues[0][1] + 2 * inValues[0][4] + 2 * inValues[0][5] + 1 * inValues[0][7] + -4 * inValues[2][1] + 2 * inValues[2][4] + -2 * inValues[2][5] + 1 * inValues[2][7] + -4 * inValues[4][1] + -2 * inValues[4][4] + 2 * inValues[4][5] + 1 * inValues[4][7] + 4 * inValues[6][1] + -2 * inValues[6][4] + -2 * inValues[6][5] + 1 * inValues[6][7];
        outCoeff[62] = -12 * inValues[0][0] + -8 * inValues[0][1] + -6 * inValues[0][2] + -6 * inValues[0][3] + -4 * inValues[0][4] + -4 * inValues[0][5] + -3 * inValues[0][6] + -2 * inValues[0][7] + 12 * inValues[1][0] + -4 * inValues[1][1] + 6 * inValues[1][2] + 6 * inValues[1][3] + -2 * inValues[1][4] + -2 * inValues[1][5] + 3 * inValues[1][6] + -1 * inValues[1][7] + 12 * inValues[2][0] + 8 * inValues[2][1] + -6 * inValues[2][2] + 6 * inValues[2][3] + -4 * inValues[2][4] + 4 * inValues[2][5] + -3 * inValues[2][6] + -2 * inValues[2][7] + -12 * inValues[3][0] + 4 * inValues[3][1] + 6 * inValues[3][2] + -6 * inValues[3][3] + -2 * inValues[3][4] + 2 * inValues[3][5] + 3 * inValues[3][6] + -1 * inValues[3][7] + 12 * inValues[4][0] + 8 * inValues[4][1] + 6 * inValues[4][2] + -6 * inValues[4][3] + 4 * inValues[4][4] + -4 * inValues[4][5] + -3 * inValues[4][6] + -2 * inValues[4][7] + -12 * inValues[5][0] + 4 * inValues[5][1] + -6 * inValues[5][2] + 6 * inValues[5][3] + 2 * inValues[5][4] + -2 * inValues[5][5] + 3 * inValues[5][6] + -1 * inValues[5][7] + -12 * inValues[6][0] + -8 * inValues[6][1] + 6 * inValues[6][2] + 6 * inValues[6][3] + 4 * inValues[6][4] + 4 * inValues[6][5] + -3 * inValues[6][6] + -2 * inValues[6][7] + 12 * inValues[7][0] + -4 * inValues[7][1] + -6 * inValues[7][2] + -6 * inValues[7][3] + 2 * inValues[7][4] + 2 * inValues[7][5] + 3 * inValues[7][6] + -1 * inValues[7][7];
        outCoeff[63] = 8 * inValues[0][0] + 4 * inValues[0][1] + 4 * inValues[0][2] + 4 * inValues[0][3] + 2 * inValues[0][4] + 2 * inValues[0][5] + 2 * inValues[0][6] + 1 * inValues[0][7] + -8 * inValues[1][0] + 4 * inValues[1][1] + -4 * inValues[1][2] + -4 * inValues[1][3] + 2 * inValues[1][4] + 2 * inValues[1][5] + -2 * inValues[1][6] + 1 * inValues[1][7] + -8 * inValues[2][0] + -4 * inValues[2][1] + 4 * inValues[2][2] + -4 * inValues[2][3] + 2 * inValues[2][4] + -2 * inValues[2][5] + 2 * inValues[2][6] + 1 * inValues[2][7] + 8 * inValues[3][0] + -4 * inValues[3][1] + -4 * inValues[3][2] + 4 * inValues[3][3] + 2 * inValues[3][4] + -2 * inValues[3][5] + -2 * inValues[3][6] + 1 * inValues[3][7] + -8 * inValues[4][0] + -4 * inValues[4][1] + -4 * inValues[4][2] + 4 * inValues[4][3] + -2 * inValues[4][4] + 2 * inValues[4][5] + 2 * inValues[4][6] + 1 * inValues[4][7] + 8 * inValues[5][0] + -4 * inValues[5][1] + 4 * inValues[5][2] + -4 * inValues[5][3] + -2 * inValues[5][4] + 2 * inValues[5][5] + -2 * inValues[5][6] + 1 * inValues[5][7] + 8 * inValues[6][0] + 4 * inValues[6][1] + -4 * inValues[6][2] + -4 * inValues[6][3] + -2 * inValues[6][4] + -2 * inValues[6][5] + 2 * inValues[6][6] + 1 * inValues[6][7] + -8 * inValues[7][0] + 4 * inValues[7][1] + 4 * inValues[7][2] + 4 * inValues[7][3] + -2 * inValues[7][4] + -2 * inValues[7][5] + -2 * inValues[7][6] + 1 * inValues[7][7];
    }

#ifdef ENOKI_AVAILABLE
    using vec4 = enoki::Array<float, 4>;

    inline static float interpolateValue(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        vec4 x1(1.0f, fracPart[0], fracPart[0] * fracPart[0], fracPart[0] * fracPart[0] * fracPart[0]);
        vec4 x2 = fracPart[1] * x1;
        vec4 x3 = fracPart[1] * x2;
        vec4 x4 = fracPart[1] * x3;

        vec4 valArray1 = enoki::load_unaligned<vec4>(&values[0]);
        vec4 valArray2 = enoki::load_unaligned<vec4>((&values[0]) + 4);
        vec4 valArray3 = enoki::load_unaligned<vec4>((&values[0]) + 8);
        vec4 valArray4 = enoki::load_unaligned<vec4>((&values[0]) + 12);
        float sum = enoki::dot(x1, valArray1) + enoki::dot(x2, valArray2) + enoki::dot(x3, valArray3) + enoki::dot(x4, valArray4);

        x1 = fracPart[2] * x1;
        x2 = fracPart[2] * x2;
        x3 = fracPart[2] * x3;
        x4 = fracPart[2] * x4;

        valArray1 = enoki::load_unaligned<vec4>(&values[0] + 16);
        valArray2 = enoki::load_unaligned<vec4>((&values[0]) + 4 + 16);
        valArray3 = enoki::load_unaligned<vec4>((&values[0]) + 8 + 16);
        valArray4 = enoki::load_unaligned<vec4>((&values[0]) + 12 + 16);
        sum += enoki::dot(x1, valArray1) + enoki::dot(x2, valArray2) + enoki::dot(x3, valArray3) + enoki::dot(x4, valArray4);

        x1 = fracPart[2] * x1;
        x2 = fracPart[2] * x2;
        x3 = fracPart[2] * x3;
        x4 = fracPart[2] * x4;

        valArray1 = enoki::load_unaligned<vec4>(&values[0] + 32);
        valArray2 = enoki::load_unaligned<vec4>((&values[0]) + 4 + 32);
        valArray3 = enoki::load_unaligned<vec4>((&values[0]) + 8 + 32);
        valArray4 = enoki::load_unaligned<vec4>((&values[0]) + 12 + 32);
        sum += enoki::dot(x1, valArray1) + enoki::dot(x2, valArray2) + enoki::dot(x3, valArray3) + enoki::dot(x4, valArray4);

        x1 = fracPart[2] * x1;
        x2 = fracPart[2] * x2;
        x3 = fracPart[2] * x3;
        x4 = fracPart[2] * x4;

        valArray1 = enoki::load_unaligned<vec4>(&values[0] + 48);
        valArray2 = enoki::load_unaligned<vec4>((&values[0]) + 4 + 48);
        valArray3 = enoki::load_unaligned<vec4>((&values[0]) + 8 + 48);
        valArray4 = enoki::load_unaligned<vec4>((&values[0]) + 12 + 48);
        sum += enoki::dot(x1, valArray1) + enoki::dot(x2, valArray2) + enoki::dot(x3, valArray3) + enoki::dot(x4, valArray4);

        return sum;
    }
#else
    inline static float interpolateValue(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        return 0.0f
         + values[0] + values[1] * fracPart[0] + values[2] * fracPart[0] * fracPart[0] + values[3] * fracPart[0] * fracPart[0] * fracPart[0] + values[4] * fracPart[1] + values[5] * fracPart[0] * fracPart[1] + values[6] * fracPart[0] * fracPart[0] * fracPart[1] + values[7] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + values[8] * fracPart[1] * fracPart[1] + values[9] * fracPart[0] * fracPart[1] * fracPart[1] + values[10] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[12] * fracPart[1] * fracPart[1] * fracPart[1] + values[13] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
         + values[16] * fracPart[2] + values[17] * fracPart[0] * fracPart[2] + values[18] * fracPart[0] * fracPart[0] * fracPart[2] + values[19] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + values[20] * fracPart[1] * fracPart[2] + values[21] * fracPart[0] * fracPart[1] * fracPart[2] + values[22] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[24] * fracPart[1] * fracPart[1] * fracPart[2] + values[25] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[28] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
         + values[32] * fracPart[2] * fracPart[2] + values[33] * fracPart[0] * fracPart[2] * fracPart[2] + values[34] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[36] * fracPart[1] * fracPart[2] * fracPart[2] + values[37] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[40] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
         + values[48] * fracPart[2] * fracPart[2] * fracPart[2] + values[49] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[52] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2];
    }
#endif

    inline static glm::vec3 interpolateGradient(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart) 
    {
        return glm::vec3(1 * values[1] + 2 * values[2] * fracPart[0] + 3 * values[3] * fracPart[0] * fracPart[0] + 1 * values[5] * fracPart[1] + 2 * values[6] * fracPart[0] * fracPart[1] + 3 * values[7] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[9] * fracPart[1] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[11] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[13] * fracPart[1] * fracPart[1] * fracPart[1] + 2 * values[14] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
                        + 1 * values[17] * fracPart[2] + 2 * values[18] * fracPart[0] * fracPart[2] + 3 * values[19] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[21] * fracPart[1] * fracPart[2] + 2 * values[22] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[23] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 1 * values[25] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 1 * values[29] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
                        + 1 * values[33] * fracPart[2] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[35] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[39] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[41] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[45] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
                        + 1 * values[49] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[50] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[54] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[57] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[61] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2],
                        1 * values[4] + 1 * values[5] * fracPart[0] + 1 * values[6] * fracPart[0] * fracPart[0] + 1 * values[7] * fracPart[0] * fracPart[0] * fracPart[0] + 2 * values[8] * fracPart[1] + 2 * values[9] * fracPart[0] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[0] * fracPart[1] + 2 * values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[12] * fracPart[1] * fracPart[1] + 3 * values[13] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
                        + 1 * values[20] * fracPart[2] + 1 * values[21] * fracPart[0] * fracPart[2] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[24] * fracPart[1] * fracPart[2] + 2 * values[25] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[28] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
                        + 1 * values[36] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[38] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[44] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
                        + 1 * values[52] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[54] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[56] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[57] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2],
                        1 * values[16] + 1 * values[17] * fracPart[0] + 1 * values[18] * fracPart[0] * fracPart[0] + 1 * values[19] * fracPart[0] * fracPart[0] * fracPart[0] + 1 * values[20] * fracPart[1] + 1 * values[21] * fracPart[0] * fracPart[1] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[24] * fracPart[1] * fracPart[1] + 1 * values[25] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[28] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
                        + 2 * values[32] * fracPart[2] + 2 * values[33] * fracPart[0] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[36] * fracPart[1] * fracPart[2] + 2 * values[37] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
                        + 3 * values[48] * fracPart[2] * fracPart[2] + 3 * values[49] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[52] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]);
    }

    inline static void interpolateVertexValues(const std::array<float, NUM_COEFFICIENTS>& values, glm::vec3 fracPart, float nodeSize, std::array<float, VALUES_PER_VERTEX>& outValues)
    {
        outValues[0] = 0.0f
         + values[0] + values[1] * fracPart[0] + values[2] * fracPart[0] * fracPart[0] + values[3] * fracPart[0] * fracPart[0] * fracPart[0] + values[4] * fracPart[1] + values[5] * fracPart[0] * fracPart[1] + values[6] * fracPart[0] * fracPart[0] * fracPart[1] + values[7] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + values[8] * fracPart[1] * fracPart[1] + values[9] * fracPart[0] * fracPart[1] * fracPart[1] + values[10] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + values[12] * fracPart[1] * fracPart[1] * fracPart[1] + values[13] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
         + values[16] * fracPart[2] + values[17] * fracPart[0] * fracPart[2] + values[18] * fracPart[0] * fracPart[0] * fracPart[2] + values[19] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + values[20] * fracPart[1] * fracPart[2] + values[21] * fracPart[0] * fracPart[1] * fracPart[2] + values[22] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + values[24] * fracPart[1] * fracPart[1] * fracPart[2] + values[25] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + values[28] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
         + values[32] * fracPart[2] * fracPart[2] + values[33] * fracPart[0] * fracPart[2] * fracPart[2] + values[34] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + values[36] * fracPart[1] * fracPart[2] * fracPart[2] + values[37] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + values[40] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
         + values[48] * fracPart[2] * fracPart[2] * fracPart[2] + values[49] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + values[52] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2];

        outValues[1] = (1 * values[1] + 2 * values[2] * fracPart[0] + 3 * values[3] * fracPart[0] * fracPart[0] + 1 * values[5] * fracPart[1] + 2 * values[6] * fracPart[0] * fracPart[1] + 3 * values[7] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[9] * fracPart[1] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[11] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[13] * fracPart[1] * fracPart[1] * fracPart[1] + 2 * values[14] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
         + 1 * values[17] * fracPart[2] + 2 * values[18] * fracPart[0] * fracPart[2] + 3 * values[19] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[21] * fracPart[1] * fracPart[2] + 2 * values[22] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[23] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 1 * values[25] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 1 * values[29] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
         + 1 * values[33] * fracPart[2] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[35] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[39] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[41] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 1 * values[45] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
         + 1 * values[49] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[50] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[54] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[57] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[61] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2]) / nodeSize;

        outValues[2] = (1 * values[4] + 1 * values[5] * fracPart[0] + 1 * values[6] * fracPart[0] * fracPart[0] + 1 * values[7] * fracPart[0] * fracPart[0] * fracPart[0] + 2 * values[8] * fracPart[1] + 2 * values[9] * fracPart[0] * fracPart[1] + 2 * values[10] * fracPart[0] * fracPart[0] * fracPart[1] + 2 * values[11] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[12] * fracPart[1] * fracPart[1] + 3 * values[13] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[14] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[15] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
         + 1 * values[20] * fracPart[2] + 1 * values[21] * fracPart[0] * fracPart[2] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[2] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[24] * fracPart[1] * fracPart[2] + 2 * values[25] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[28] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
         + 1 * values[36] * fracPart[2] * fracPart[2] + 1 * values[37] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[38] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 1 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[44] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
         + 1 * values[52] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[53] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[54] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 1 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[56] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[57] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2]) / nodeSize;

        outValues[3] = (1 * values[16] + 1 * values[17] * fracPart[0] + 1 * values[18] * fracPart[0] * fracPart[0] + 1 * values[19] * fracPart[0] * fracPart[0] * fracPart[0] + 1 * values[20] * fracPart[1] + 1 * values[21] * fracPart[0] * fracPart[1] + 1 * values[22] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[24] * fracPart[1] * fracPart[1] + 1 * values[25] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[28] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 1 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
         + 2 * values[32] * fracPart[2] + 2 * values[33] * fracPart[0] * fracPart[2] + 2 * values[34] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[35] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[36] * fracPart[1] * fracPart[2] + 2 * values[37] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[40] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[41] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[44] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
         + 3 * values[48] * fracPart[2] * fracPart[2] + 3 * values[49] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[50] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[51] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[52] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[53] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[54] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[56] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[57] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[60] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]) / nodeSize;


        const float sqNodeSize = nodeSize * nodeSize;
        outValues[4] = (1 * values[5] + 2 * values[6] * fracPart[0] + 3 * values[7] * fracPart[0] * fracPart[0] + 2 * values[9] * fracPart[1] + 4 * values[10] * fracPart[0] * fracPart[1] + 6 * values[11] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[13] * fracPart[1] * fracPart[1] + 6 * values[14] * fracPart[0] * fracPart[1] * fracPart[1] + 9 * values[15] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
         + 1 * values[21] * fracPart[2] + 2 * values[22] * fracPart[0] * fracPart[2] + 3 * values[23] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[25] * fracPart[1] * fracPart[2] + 4 * values[26] * fracPart[0] * fracPart[1] * fracPart[2] + 6 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 3 * values[29] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 9 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
         + 1 * values[37] * fracPart[2] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[39] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 2 * values[41] * fracPart[1] * fracPart[2] * fracPart[2] + 4 * values[42] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[45] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]
         + 1 * values[53] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[54] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] * fracPart[2] + 2 * values[57] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 4 * values[58] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 6 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 6 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2] + 9 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] * fracPart[2]) / sqNodeSize;
        
        outValues[5] = (1 * values[17] + 2 * values[18] * fracPart[0] + 3 * values[19] * fracPart[0] * fracPart[0] + 1 * values[21] * fracPart[1] + 2 * values[22] * fracPart[0] * fracPart[1] + 3 * values[23] * fracPart[0] * fracPart[0] * fracPart[1] + 1 * values[25] * fracPart[1] * fracPart[1] + 2 * values[26] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 1 * values[29] * fracPart[1] * fracPart[1] * fracPart[1] + 2 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1]
         + 2 * values[33] * fracPart[2] + 4 * values[34] * fracPart[0] * fracPart[2] + 6 * values[35] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[37] * fracPart[1] * fracPart[2] + 4 * values[38] * fracPart[0] * fracPart[1] * fracPart[2] + 6 * values[39] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 2 * values[41] * fracPart[1] * fracPart[1] * fracPart[2] + 4 * values[42] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 2 * values[45] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 4 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2]
         + 3 * values[49] * fracPart[2] * fracPart[2] + 6 * values[50] * fracPart[0] * fracPart[2] * fracPart[2] + 9 * values[51] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[53] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[54] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[55] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[57] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[58] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 3 * values[61] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]) / sqNodeSize;
        
        outValues[6] = (1 * values[20] + 1 * values[21] * fracPart[0] + 1 * values[22] * fracPart[0] * fracPart[0] + 1 * values[23] * fracPart[0] * fracPart[0] * fracPart[0] + 2 * values[24] * fracPart[1] + 2 * values[25] * fracPart[0] * fracPart[1] + 2 * values[26] * fracPart[0] * fracPart[0] * fracPart[1] + 2 * values[27] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[28] * fracPart[1] * fracPart[1] + 3 * values[29] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[30] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] + 3 * values[31] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
         + 2 * values[36] * fracPart[2] + 2 * values[37] * fracPart[0] * fracPart[2] + 2 * values[38] * fracPart[0] * fracPart[0] * fracPart[2] + 2 * values[39] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] + 4 * values[40] * fracPart[1] * fracPart[2] + 4 * values[41] * fracPart[0] * fracPart[1] * fracPart[2] + 4 * values[42] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 4 * values[43] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 6 * values[44] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[45] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[46] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 6 * values[47] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
         + 3 * values[52] * fracPart[2] * fracPart[2] + 3 * values[53] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[54] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 3 * values[55] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 6 * values[56] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[57] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[58] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 6 * values[59] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[60] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[61] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[62] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[63] * fracPart[0] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]) / sqNodeSize;
        
        outValues[7] = (1 * values[21] + 2 * values[22] * fracPart[0] + 3 * values[23] * fracPart[0] * fracPart[0] + 2 * values[25] * fracPart[1] + 4 * values[26] * fracPart[0] * fracPart[1] + 6 * values[27] * fracPart[0] * fracPart[0] * fracPart[1] + 3 * values[29] * fracPart[1] * fracPart[1] + 6 * values[30] * fracPart[0] * fracPart[1] * fracPart[1] + 9 * values[31] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1]
         + 2 * values[37] * fracPart[2] + 4 * values[38] * fracPart[0] * fracPart[2] + 6 * values[39] * fracPart[0] * fracPart[0] * fracPart[2] + 4 * values[41] * fracPart[1] * fracPart[2] + 8 * values[42] * fracPart[0] * fracPart[1] * fracPart[2] + 12 * values[43] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] + 6 * values[45] * fracPart[1] * fracPart[1] * fracPart[2] + 12 * values[46] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] + 18 * values[47] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2]
         + 3 * values[53] * fracPart[2] * fracPart[2] + 6 * values[54] * fracPart[0] * fracPart[2] * fracPart[2] + 9 * values[55] * fracPart[0] * fracPart[0] * fracPart[2] * fracPart[2] + 6 * values[57] * fracPart[1] * fracPart[2] * fracPart[2] + 12 * values[58] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 18 * values[59] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[2] * fracPart[2] + 9 * values[61] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 18 * values[62] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2] + 27 * values[63] * fracPart[0] * fracPart[0] * fracPart[1] * fracPart[1] * fracPart[2] * fracPart[2]) / (sqNodeSize * nodeSize);
    }
};
}

#endif
